﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using pswb.Controls;
using pswb.Forms.Wizard;
using pswb.Classes;
using WeifenLuo.WinFormsUI.Docking;

namespace pswb.Forms.ProcessEdit
{
    public partial class frmDocument : DockContent
    {
        #region Properties
        [Browsable(false)]
        public bool isNew { get; set; }

        [Browsable(false)]
        public bool isSaved { get; set; }

        [CategoryAttribute("All"), DescriptionAttribute("Location of the physical file where process is saved")]
        public string Filename { get; private set; }

        [CategoryAttribute("All"), DescriptionAttribute("Friendly name of the process")]
        public string ProcessName { get; set; }

        private Guid _ID;
        [CategoryAttribute("All"), DescriptionAttribute("Unique ID of the process")]
        public Guid ID
        {
            get { return _ID; }
        }
        
        #endregion

        #region Private Variables
        private int _sectionNumber = 1;
        
        private delegate void invokeDelegate();
        #endregion

        #region Public Variables
        public event EventHandler onFieldSelect;
        #endregion

        #region Constructor
        public frmDocument()
        {
            InitializeComponent();
        }
        #endregion

        #region Private Methods
        private void frmDocument_Load(object sender, EventArgs e)
        {
            if (isNew)
            {
                frmProcessProperties prop = new frmProcessProperties();
                if (prop.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    ProcessName = prop.ProcessName;
                    this.Text = prop.ProcessName;
                }
                else
                {
                    this.BeginInvoke(new invokeDelegate(CloseThisDocument));
                }
                _ID = Guid.NewGuid();
            }
            isSaved = true;
            pnlStage.AllowDrop = true;
        }

        private void CloseThisDocument()
        {
            this.Close();
        }

        private void frmDocument_DragEnter(object sender, DragEventArgs e)
        {
            if (e.AllowedEffect == DragDropEffects.Copy)
            {
                LinkLabel lb = e.Data.GetData(typeof(LinkLabel)) as LinkLabel;
                if (lb.Text == "Section")
                {
                    e.Effect = DragDropEffects.Copy;
                }
            }
        }

        private void frmDocument_DragDrop(object sender, DragEventArgs e)
        {
            //add a section
            ProcessSection section = CreateSection();
            pnlStage.Controls.Add(section);
            if (isSaved)
            {
                this.Text = "*" + this.Text;
                isSaved = false;
            }
        }

        private void pnlStage_DragEnter(object sender, DragEventArgs e)
        {
            if (e.AllowedEffect == DragDropEffects.Copy)
            {
                LinkLabel lb = e.Data.GetData(typeof(LinkLabel)) as LinkLabel;
                if (lb.Text == "Section")
                {
                    e.Effect = DragDropEffects.Copy;
                }
            }
        }

        private void pnlStage_DragDrop(object sender, DragEventArgs e)
        {
            //add a section
            ProcessSection section = CreateSection();
            pnlStage.Controls.Add(section);
            if (isSaved)
            {
                this.Text = "*" + this.Text;
                isSaved = false;
            }
        }

        private ProcessSection CreateSection()
        {
            ProcessSection section = new ProcessSection();
            Padding pad = new Padding(20);
            section.Dock = DockStyle.Bottom;
            section.SectionTitle = string.Format("Section {0}", _sectionNumber++);
            section.onFieldSelect += new EventHandler(section_onFieldSelect);
            section.onChange += new EventHandler(section_onChange);
            onFieldSelect(section, new EventArgs());

            return section;
        }

        void section_onChange(object sender, EventArgs e)
        {
            if (isSaved)
            {
                this.Text = "*" + this.Text;
                isSaved = false;
            }
        }
        
        void section_onFieldSelect(object sender, EventArgs e)
        {
            onFieldSelect(sender, e);
        }

        private void pnlStage_Click(object sender, EventArgs e)
        {
            onFieldSelect(this, e);
        }

        private void frmDocument_Click(object sender, EventArgs e)
        {
            onFieldSelect(this, e);
        }
        #endregion

        #region Public Methods
        public void SaveProcess(string fileName)
        {
            if (fileName == null || fileName == string.Empty) return;
            XmlTextWriter w = new XmlTextWriter(fileName, Encoding.ASCII);
            w.WriteStartDocument(true);
            w.WriteComment("Auto generated code, do not change");
            w.WriteStartElement("Process");
            w.WriteStartElement("Header");
            w.WriteAttributeString("ID", ID.ToString());
            w.WriteAttributeString("Name", ProcessName);
            w.WriteAttributeString("Version", "0");
            w.WriteEndElement();
            //put sections
            foreach (Control c in pnlStage.Controls)
            {
                if (c.GetType() == typeof(ProcessSection))
                {
                    ProcessSection section = c as ProcessSection;
                    w.WriteStartElement("Section");
                    w.WriteAttributeString("Name", section.SectionTitle);
                    w.WriteStartElement("Fields");
                    //put fields
                    foreach (Panel pnl in section.Controls)
                    {
                        foreach (Control ctrl in pnl.Controls)
                        {
                            if (ctrl.GetType() == typeof(TableLayoutPanel))
                            {
                                TableLayoutPanel table = ctrl as TableLayoutPanel;
                                foreach (FieldTypeDisplay field in table.Controls)
                                {
                                    w.WriteStartElement("Field");
                                    w.WriteAttributeString("ID", field.ID.ToString());
                                    w.WriteAttributeString("Label", field.Label);
                                    w.WriteAttributeString("Type", "TextBox");
                                    w.WriteAttributeString("Row", field.Row.ToString());
                                    w.WriteAttributeString("Column", field.Column.ToString());
                                    w.WriteAttributeString("RowSpan", field.RowSpan.ToString());
                                    w.WriteAttributeString("ColSpan", field.ColumnSpan.ToString());
                                    w.WriteEndElement();
                                }
                            }
                        }
                    }
                    w.WriteEndElement();
                    w.WriteEndElement();
                }
            }
            w.WriteEndElement();
            w.Flush();
            w.Close();
            if(this.Text.Substring(0,1)=="*")
                this.Text = this.Text.Substring(1);
            isSaved = true;
            Filename = fileName;
        }

        public void LoadProcess(string fileName)
        {
            if (fileName == null || fileName == string.Empty)
                throw new Exception("Invalid file");
            if (!File.Exists(fileName))
                throw new Exception("Can not find the file specified.");
            XmlDocument xDoc = new XmlDocument();
            try
            {
                //xDoc.Load(fileName);
                XmlTextReader reader = new XmlTextReader(fileName);
                reader.MoveToContent();
                XmlNode node = xDoc.ReadNode(reader); //Process node
                XmlNode header = node.FirstChild; //Header node
                if (header.Attributes.Count != 3)
                    throw new Exception("Invalid process definition");
                this.Filename = fileName;
                _ID = new Guid(header.Attributes[0].Value);
                this.ProcessName = header.Attributes[1].Value;
                this.Text = this.ProcessName;
                string ProcessVersion = header.Attributes[2].Value;

                foreach (XmlNode section in node.ChildNodes)
                {
                    if (section.Name == "Section")
                    {
                        ProcessSection sec = new ProcessSection();
                        Padding pad = new Padding(20);
                        sec.Dock = DockStyle.Bottom;
                        sec.SectionTitle = section.Attributes[0].Value;
                        sec.onFieldSelect += new EventHandler(section_onFieldSelect);
                        sec.onChange += new EventHandler(section_onChange);
                        pnlStage.Controls.Add(sec);

                        //find fields
                        XmlNode fields = section.FirstChild;
                        foreach (XmlNode field in fields.ChildNodes)
                        {
                            if (field.Name == "Field")
                            {
                                Guid id = new Guid(field.Attributes[0].Value);
                                int col = int.Parse(field.Attributes[4].Value);
                                int row = int.Parse(field.Attributes[3].Value);
                                int colspan = int.Parse(field.Attributes[6].Value);
                                int rowspan = int.Parse(field.Attributes[5].Value);
                                string label = field.Attributes[1].Value;
                                sec.AddField(id, label, row, col, rowspan, colspan);
                            }
                        }
                    }
                }
                reader.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        
    }
}
